home *** CD-ROM | disk | FTP | other *** search
- /* bobmem.c - memory manager */
- /*
- Copyright (c) 1991, by David Michael Betz
- All rights reserved
- */
-
- #include <setjmp.h>
- #include "bob.h"
-
- /* allocation unit */
- typedef char *AUNIT;
- #define ALLOCSIZE(x) (((x) + sizeof(AUNIT) - 1) / sizeof(AUNIT))
-
- /* block flags */
- #define MARK 1
-
- /* size of each type of memory segment */
- #define VSSIZE 10000 /* number of LVAL's per vector segment */
- #define VCOMPARE(f,s,t) ((f) + (s) <= (t))
-
- /* macros to compute the size of a segment */
- #define vsegsize(n) (sizeof(VSEGMENT)+((n)-1)*sizeof(char *))
-
- /* macro to convert a byte size to a word size */
- #define btow_size(n) (((n) + sizeof(char *) - 1) / sizeof(char *))
-
- /* vector segment structure */
- typedef struct vsegment {
- struct vsegment *vs_next; /* next vector segment */
- AUNIT *vs_free; /* next free location in this segment */
- AUNIT *vs_top; /* top of segment (plus one) */
- AUNIT vs_data[1]; /* segment data */
- } VSEGMENT;
-
- /* global variables */
- VALUE symbols; /* the symbol table */
- VALUE classes; /* the class table */
- VALUE nil; /* the nil value */
-
- /* vector (and string) space */
- static VSEGMENT *vsegments=NULL;/* list of vector segments */
- static VSEGMENT *vscurrent=NULL;/* current vector segment */
- static AUNIT *vfree=NULL; /* next free location in current segment */
- static AUNIT *vtop=NULL; /* top of current segment */
-
- /* external variables */
- extern jmp_buf error_trap; /* the error trap target */
- extern VECTOR *code; /* currently executing code vector */
-
- /* forward declarations */
- void mark();
- static HDR *allocmemory();
- static void gc(),markclass(),markdictionary(),markentry(),markobject();
- static void markvector(),compact(),compact_vector();
- static DICT_ENTRY *newentry();
-
- /* initialize - initialize the virtual machine */
- int initialize(smax,cmax)
- int smax,cmax;
- {
- int obj_class(),cls_new();
- char *calloc();
-
- /* setup an error trap handler */
- if (setjmp(error_trap) != 0)
- return (FALSE);
-
- /* allocate the stack */
- if ((stkbase = (VALUE *)calloc(1,smax * sizeof(VALUE))) == NULL)
- return (FALSE);
- stktop = sp = stkbase + smax;
- code = NULL;
-
- /* initialize the memory manager */
- vsegments = vscurrent = NULL;
- vfree = vtop = NULL;
- if (!vexpand(VSSIZE))
- return (FALSE);
-
- /* initialize the compiler */
- if (!init_compiler(cmax))
- return (FALSE);
-
- /* create the symbol and class tables */
- set_nil(&nil);
- set_dictionary(&symbols,newdictionary(&nil));
- set_dictionary(&classes,newdictionary(&nil));
-
- /* enter the built-in functions */
- init_functions();
- return (TRUE);
- }
-
- /* addentry - add an entry to a dictionary */
- DICT_ENTRY *addentry(dict,key,type)
- VALUE *dict; char *key; int type;
- {
- DICT_ENTRY *entry;
- if ((entry = findentry(dict,key)) == NULL) {
- check(1);
- push_var(newentry(dict,key,type));
- sp->v.v_var->de_next = *digetcontents(dict);
- dict->v.v_dictionary->di_contents = *sp;
- entry = deaddr(sp++);
- }
- return (entry);
- }
-
- /* findentry - find an entry in a dictionary */
- DICT_ENTRY *findentry(dict,key)
- VALUE *dict; char *key;
- {
- DICT_ENTRY *entry;
- for (entry = digetcontents(dict)->v.v_var;
- entry != NULL;
- entry = entry->de_next.v.v_var)
- if (strncmp(key,
- strgetdata(&entry->de_key),
- strgetsize(&entry->de_key)) == 0)
- return (entry);
- return (NULL);
- }
-
- /* makestring - make an initialized string from a C-style string */
- STRING *makestring(str)
- char *str;
- {
- STRING *val;
- int len;
- len = strlen(str);
- val = newstring(len);
- strncpy(val->str_data,str,len);
- return (val);
- }
-
- /* getcstring - get a C-style version of a string */
- char *getcstring(buf,max,str)
- char *buf; int max; VALUE *str;
- {
- int len;
- if ((len = strgetsize(str)) >= max)
- len = max - 1;
- strncpy(buf,strgetdata(str),len);
- buf[len] = '\0';
- return (buf);
- }
-
- /* newstring - allocate a new string object */
- STRING *newstring(n)
- int n;
- {
- STRING *val;
- int size;
- char *p;
- size = sizeof(STRING) + n - 1;
- val = (STRING *)allocmemory(DT_STRING,size);
- val->str_size = n;
- for (p = val->str_data; --n >= 0; )
- *p++ = '\0';
- return (val);
- }
-
- /* newobject - allocate a new object */
- OBJECT *newobject(class)
- VALUE *class;
- {
- OBJECT *val;
- int size,n;
- VALUE *p;
- n = clgetsize(class);
- size = sizeof(OBJECT) + (n - 1) * sizeof(VALUE);
- val = (OBJECT *)allocmemory(DT_OBJECT,size);
- val->obj_class = *class;
- for (p = val->obj_members; --n >= 0; ++p)
- p->v_type = DT_NIL;
- return (val);
- }
-
- /* newvector - allocate a new vector */
- VECTOR *newvector(n)
- int n;
- {
- VECTOR *val;
- VALUE *p;
- int size;
- size = sizeof(VECTOR) + (n - 1) * sizeof(VALUE);
- val = (VECTOR *)allocmemory(DT_VECTOR,size);
- val->vec_size = n;
- for (p = val->vec_data; --n >= 0; ++p)
- p->v_type = DT_NIL;
- return (val);
- }
-
- /* newclass - create a new class */
- CLASS *newclass(name,base)
- char *name; VALUE *base;
- {
- /* allocate the memory for the new class */
- check(1);
- push_class((CLASS *)allocmemory(DT_CLASS,sizeof(CLASS)));
- set_nil(&sp->v.v_class->cl_name);
- set_nil(&sp->v.v_class->cl_members);
- set_nil(&sp->v.v_class->cl_functions);
-
- /* initialize */
- sp->v.v_class->cl_base = *base;
- set_string(&sp->v.v_class->cl_name,makestring(name));
- set_dictionary(&sp->v.v_class->cl_members,newdictionary(sp));
- set_dictionary(&sp->v.v_class->cl_functions,newdictionary(sp));
- sp->v.v_class->cl_size = 0;
-
- /* return the new class */
- return (claddr(sp++));
- }
-
- /* newdictionary - create a new dictionary */
- DICTIONARY *newdictionary(class)
- VALUE *class;
- {
- DICTIONARY *dict;
- dict = (DICTIONARY *)allocmemory(DT_DICTIONARY,sizeof(DICTIONARY));
- dict->di_class = *class;
- set_nil(&dict->di_contents);
- return (dict);
- }
-
- /* newentry - allocate a new dictionary entry */
- static DICT_ENTRY *newentry(dict,key,type)
- VALUE *dict; char *key; int type;
- {
- check(1);
- push_var((DICT_ENTRY *)allocmemory(DT_VAR,sizeof(DICT_ENTRY)));
- sp->v.v_var->de_dictionary = *dict;
- sp->v.v_var->de_type = type;
- set_nil(&sp->v.v_var->de_key);
- set_nil(&sp->v.v_var->de_value);
- set_nil(&sp->v.v_var->de_next);
- set_string(&sp->v.v_var->de_key,makestring(key));
- return (deaddr(sp++));
- }
-
- /* allocmemory - allocate a block of memory */
- static HDR *allocmemory(type,size)
- int type,size;
- {
- HDR *val;
-
- /* make sure there's enough space */
- size = ALLOCSIZE(size);
- if (!VCOMPARE(vfree,size,vtop)
- && !checkvmemory(size)
- && !findvmemory(size))
- error("Insufficient memory");
-
- /* allocate the next available block */
- val = (HDR *)vfree;
- vfree += size;
-
- /* return the new block of memory */
- val->hdr_type = type;
- val->hdr_flags = 0;
- val->hdr_chain = NULL;
- /*printf("ALLOC: %04x T:%02d S:%d\n",val,type,size);*/
- return (val);
- }
-
- /* findvmemory - find vector memory */
- static int findvmemory(size)
- int size;
- {
- /* try garbage collecting */
- gc();
-
- /* check to see if we found enough memory */
- if (VCOMPARE(vfree,size,vtop) || checkvmemory(size))
- return (TRUE);
-
- /* expand vector space */
- return (makevmemory(size));
- }
-
- /* checkvmemory - check for vector memory (used by 'xsimage.c') */
- static int checkvmemory(size)
- int size;
- {
- VSEGMENT *vseg;
- for (vseg = vsegments; vseg != NULL; vseg = vseg->vs_next)
- if (vseg != vscurrent && VCOMPARE(vseg->vs_free,size,vseg->vs_top)) {
- if (vscurrent != NULL)
- vscurrent->vs_free = vfree;
- vfree = vseg->vs_free;
- vtop = vseg->vs_top;
- vscurrent = vseg;
- return (TRUE);
- }
- return (FALSE);
- }
-
- /* makevmemory - make vector memory (used by 'xsimage.c') */
- static int makevmemory(size)
- int size;
- {
- return (vexpand(size < VSSIZE ? VSSIZE : size));
- }
-
- /* vexpand - expand vector space */
- static int vexpand(size)
- int size;
- {
- VSEGMENT *newvsegment(),*vseg;
-
- /* allocate the new segment */
- if ((vseg = newvsegment(size)) != NULL) {
-
- /* initialize the new segment and make it current */
- if (vscurrent != NULL)
- vscurrent->vs_free = vfree;
- vfree = vseg->vs_free;
- vtop = vseg->vs_top;
- vscurrent = vseg;
- }
- return (vseg != NULL);
- }
-
- /* newvsegment - create a new vector segment */
- static VSEGMENT *newvsegment(n)
- unsigned int n;
- {
- char *calloc();
- VSEGMENT *newseg;
-
- /* allocate the new segment */
- if ((newseg = (VSEGMENT *)calloc(1,vsegsize(n))) == NULL)
- return (NULL);
-
- /* initialize the new segment */
- newseg->vs_free = newseg->vs_data;
- newseg->vs_top = newseg->vs_free + n;
- newseg->vs_next = vsegments;
- vsegments = newseg;
-
- /* return the new segment */
- return (newseg);
- }
-
- /* gc - garbage collect */
- static void gc()
- {
- extern unsigned char *cbase,*pc;
- VALUE codeval,*p;
- LITERAL *lit;
- int pcoff;
-
- /*printf("[GC]\n");*/
- /* protect the current bytecode vector */
- if (code) {
- set_bytecode(&codeval,code);
- pcoff = pc - cbase;
- mark(&codeval);
- }
-
- /* mark all reachable values */
- mark(&symbols);
- mark(&classes);
-
- /* mark the stack */
- for (p = sp; p < stktop; )
- mark(p++);
-
- /* mark compiler variables */
- mark_compiler();
-
- /* compact all active blocks */
- compact();
-
- /* reload the interpreter's registers */
- if (code) {
- code = codeval.v.v_vector;
- cbase = code->vec_data[0].v.v_string->str_data;
- pc = cbase + pcoff;
- }
- }
-
- /* mark - mark all accessible nodes */
- void mark(val)
- VALUE *val;
- {
- HDR *hdr;
- /*printf("MARKING: %04x T:%02d H:%04x\n",val,val->v_type,val->v.v_hdr);*/
- switch (val->v_type) {
- case DT_CLASS:
- case DT_OBJECT:
- case DT_VECTOR:
- case DT_BYTECODE:
- case DT_STRING:
- case DT_DICTIONARY:
- case DT_VAR:
- hdr = val->v.v_hdr;
- val->v.v_chain = hdr->hdr_chain;
- hdr->hdr_chain = val;
- if ((hdr->hdr_flags & MARK) == 0) {
- hdr->hdr_flags |= MARK;
- switch (hdr->hdr_type) {
- case DT_CLASS:
- markclass((CLASS *)hdr);
- break;
- case DT_OBJECT:
- markobject((OBJECT *)hdr);
- break;
- case DT_VECTOR:
- markvector((VECTOR *)hdr);
- break;
- case DT_DICTIONARY:
- markdictionary((DICTIONARY *)hdr);
- break;
- case DT_VAR:
- markentry((DICT_ENTRY *)hdr);
- break;
- }
- }
- break;
- }
- }
-
- /* markclass - mark a class */
- static void markclass(class)
- CLASS *class;
- {
- mark(&class->cl_name);
- mark(&class->cl_base);
- mark(&class->cl_members);
- mark(&class->cl_functions);
- }
-
- /* markdictionary - mark a dictionary */
- static void markdictionary(dict)
- DICTIONARY *dict;
- {
- VALUE *next,*val;
- mark(&dict->di_class);
- for (val = &dict->di_contents;
- !isnil(val);
- val = next) {
- next = degetnext(val);
- mark(val);
- }
- }
-
- /* markentry - mark a dictionary entry */
- static void markentry(entry)
- DICT_ENTRY *entry;
- {
- mark(&entry->de_dictionary);
- mark(&entry->de_key);
- mark(&entry->de_value);
- }
-
- /* markobject - mark an object */
- static void markobject(obj)
- OBJECT *obj;
- {
- VALUE *p;
- int n;
- p = obj->obj_members;
- n = clgetsize(&obj->obj_class);
- while (--n >= 0)
- mark(p++);
- }
-
- /* markvector - mark a vector */
- static void markvector(vect)
- VECTOR *vect;
- {
- VALUE *p;
- int n;
- p = vect->vec_data;
- n = vect->vec_size;
- while (--n >= 0)
- mark(p++);
- }
-
- /* compact - compact vector space */
- static void compact()
- {
- VSEGMENT *vseg;
-
- /* store the current segment information */
- if (vscurrent)
- vscurrent->vs_free = vfree;
-
- /* compact each vector segment */
- for (vseg = vsegments; vseg != NULL; vseg = vseg->vs_next)
- compact_vector(vseg);
-
- /* make the first vector segment current */
- if ((vscurrent = vsegments) != NULL) {
- vfree = vscurrent->vs_free;
- vtop = vscurrent->vs_top;
- }
- }
-
- /* getblocksize - get the size of a block */
- static int getblocksize(hdr)
- HDR *hdr;
- {
- switch (hdr->hdr_type) {
- case DT_CLASS:
- return (ALLOCSIZE(sizeof(CLASS)));
- case DT_OBJECT:
- return (ALLOCSIZE(sizeof(OBJECT)
- + (clgetsize(&((OBJECT *)hdr)->obj_class) - 1) * sizeof(VALUE)));
- case DT_VECTOR:
- return (ALLOCSIZE(sizeof(VECTOR)
- + (((VECTOR *)hdr)->vec_size - 1) * sizeof(VALUE)));
- case DT_STRING:
- return (ALLOCSIZE(sizeof(STRING)
- + ((STRING *)hdr)->str_size - 1));
- case DT_DICTIONARY:
- return (ALLOCSIZE(sizeof(DICTIONARY)));
- case DT_VAR:
- return (ALLOCSIZE(sizeof(DICT_ENTRY)));
- }
- error("Bad block type: %d",hdr->hdr_type);
- return (0);
- }
-
- /* compact_vector - compact a vector segment */
- static void compact_vector(vseg)
- VSEGMENT *vseg;
- {
- AUNIT *vdata,*vnext,*vfree;
- VALUE *vp,*nextvp;
- int vsize;
- HDR *hdr;
-
- vdata = vnext = vseg->vs_data;
- vfree = vseg->vs_free;
- while (vdata < vfree) {
- hdr = (HDR *)vdata;
- vsize = getblocksize(hdr);
- if (hdr->hdr_flags & MARK) {
- hdr->hdr_flags &= ~MARK;
- for (vp = hdr->hdr_chain; vp != NULL; vp = nextvp) {
- nextvp = vp->v.v_chain;
- /*printf("FIXUP: H:%04x T:%02d V:%04x C:%04x N:%04x\n",
- hdr,hdr->hdr_type,vp,nextvp,vnext);*/
- vp->v.v_hdr = (HDR *)vnext;
- }
- hdr->hdr_chain = NULL;
- if (vdata == vnext) {
- /*printf("KEEPING: %04x T:%02d\n",hdr,hdr->hdr_type);*/
- vdata += vsize;
- vnext += vsize;
- }
- else {
- /*printf("MOVING: %04x->%04x T:%02d\n",hdr,vnext,hdr->hdr_type);*/
- while (--vsize >= 0)
- *vnext++ = *vdata++;
- }
- }
- else {
- /*printf("FREEING: %04x T:%02d\n",hdr,hdr->hdr_type);*/
- vdata += vsize;
- }
- }
- vseg->vs_free = vnext;
- }